#include "monitor.h"
#include <QtCore/qmath.h>
#include <QtDeclarative>


CfgMonitor::CfgMonitor( QObject *_parent, QNMSettings * qset) : QObject(_parent), parent( _parent )
{
    ifaceMonitor = qset->getIfaceMonitor();
    listIfaces = qset->getListIfaces();
}

void CfgMonitor::initListIfaces()
{

    int selectedIndexIfaceMonitor = 0;
    QString selectedIfaceMonitor = listIfaces.at( selectedIndexIfaceMonitor );

    int J = 0;
    IfaceListModel *listModel = new IfaceListModel( this );

    for( int z=0; z<listIfaces.length(); z++ )
    {
        QString strIfacePic = Utils::pixmapIface( listIfaces.at(z) );
        QString ifaceName = listIfaces.at(z);
        IfaceItemModel *item = new IfaceItemModel( ifaceName, strIfacePic, this );
        listModel->append( item );
        if( ifaceMonitor == ifaceName ) {
            selectedIndexIfaceMonitor = J;
            selectedIfaceMonitor = ifaceName;
        }
        J++;
    }
    //qDebug() << "cppSelectedIndexIfacesMonitor="+selectedIndexIfaceMonitor;
    //qDebug() << "cppSelectedIfaceMonitor="+selectedIfaceMonitor;

    QDeclarativeView *qmlObj = (QDeclarativeView*)(this->parent);
    QDeclarativeEngine *engine = qmlObj->engine();
    engine->rootContext()->setContextProperty( "listIfacesMonitor", listModel );
    engine->rootContext()->setContextProperty( "cppSelectedIndexIfacesMonitor", selectedIndexIfaceMonitor );
    engine->rootContext()->setContextProperty( "cppSelectedIfaceMonitor", selectedIfaceMonitor );

}

/**********************************************************************************************************/

Monitor::Monitor(QDeclarativeItem *parent) : QDeclarativeItem(parent)
{
    this->setFlag( QDeclarativeItem::ItemHasNoContents, false );

    qset_here = new QNMSettings( this );

    timeout = 1;
    timer.setInterval( timeout*1000 );
    QObject::connect( &timer, SIGNAL(timeout()), this, SLOT(getTraffData()) );

    iface = "wlan0";

    /* временные параметры графика */
    __timestamp = 30;

    /* размеры графика в ландшафтном режиме */
    LX_l = 845; LY_l = 380;
    /* размеры графика в портретном режиме */
    LX_p = 470; LY_p = 735;

    shiftX = 10; lenghtX = LX_l;
    shiftY = 30; lenghtY = LX_p;

    /* длина графика по Y */
    Ly = lenghtX - shiftX;
    /* длина графика по X */
    Lx = lenghtY - shiftY;

    /* ширина линии графика */
    pxLenGraph = 4;

    viewTimestampMarker.enqueue(-1);

    __showRX = true;
    __showTX = true;

    __typeGraph = GRAPH_TIME_TYPE;
    //__typeGraph = GRAPH_STAT_TYPE;

    maxScaleY = 0;
    flFistGetTraff = false;

    /* кисть и шрифт сетки */
    penGrid.setColor( QColor(120,120,120) );
    penGrid.setWidth(1);
    penGrid.setStyle( Qt::DashLine );
    fontGrid.setPointSize( 12 );

    /* кисть и шрифт системы координат */
    penSC.setColor( QColor("gray") );
    penSC.setWidth( 4 );

    /* кисть и шрифт отрисовки интерфейса */
    penIface.setColor( QColor("white") );
    penIface.setWidth( 1 );
    fontIface.setPointSize( 12 );

    __speedRX = "000.00 kB/s";
    __speedTX = "000.00 kB/s";
    __traffRX = "000.00 kB";
    __traffTX = "000.00 kB";

    rx0 = tx0 = rx1 = tx1 = 0;

    flOnline = false;

    /* хранит время в секундах с момента запуска */
    storeTime = 0;

    /* инициализация настроек */
    this->initSettings();
}

/* поиск максимального элемента в очереди */
int Monitor::maxQQueue( const QQueue<int> &queue ) const
{
    int maxValue = 0;
    QList<int>::const_iterator itr;
    for( itr = queue.begin(); itr != queue.end(); ++itr ) {
        if( (*itr) > maxValue  ) {
            maxValue = *itr;
        }
    }
    return maxValue;
}

/* получение данных с интерфейса и отображение их на графике */
void Monitor::getTraffData()
{
    this->firstDataTraf();

    int rx = 0, tx = 0;

    GetTraff *gt = new GetTraff( iface );
    TraffData trData = gt->getCurrBytes();
    delete gt;
    //qDebug() <<  "rx=" << trData.rx << " tx=" << trData.tx;

    rx1 = trData.rx;
    tx1 = trData.tx;
    flOnline = trData.ok;

    rx = rx1 - rx0;
    tx = tx1 - tx0;

    rx0 = trData.rx;
    tx0 = trData.tx;

    rx = ( rx*1.0 ) / timeout;
    tx = ( tx*1.0 ) / timeout;
    if( (rx < 0) || (tx < 0) ) {
        /* после смены интерфейсов, заново необходимо первое считывание */
        flFistGetTraff = true;
        return;
    }

    /* проталкиваем очередное полученное значение в очередь
     * при этом "лишнюю заднюю часть" из деки отбрасываем
     */
    int dx = shiftX + pxLenGraph/2;
    while( (X+dx) > lenghtX )
    {
        viewTimestampMarker.dequeue();
        viewPointOnGraphRX.dequeue();
        viewPointOnGraphTX.dequeue();
        X = X - pxLenGraph;
    }

    viewPointOnGraphRX.enqueue( rx );
    viewPointOnGraphTX.enqueue( tx );

    if ( storeTime%__timestamp == 0 ) {
        viewTimestampMarker.enqueue( storeTime );
    } else {
        viewTimestampMarker.enqueue( -1 );
    }

    /* берем максимальное значение из каждой очереди если они рисуются обе,
     * иначе, макс. занчение графика, очередь которого будет отображаться
     */
    int maxRXTX = 0;
    if( __showRX && __showTX ) {
        int maxRX = this->maxQQueue( viewPointOnGraphRX );
        int maxTX = this->maxQQueue( viewPointOnGraphTX );
        maxRXTX = qMax( maxRX, maxTX );
    } else if( __showRX && (__showTX == false) ) {
        maxRXTX = this->maxQQueue( viewPointOnGraphRX );
    } else if( __showTX && (__showRX == false) ) {
        maxRXTX = this->maxQQueue( viewPointOnGraphTX );
    }

    /* высчитываем масштабный коэффициент */
    int m = 1;
    while( true ) {
        if( maxRXTX <= qPow(2,m) ) {
            break;
        }
        m++;
    }
    maxScaleY = qPow(2,m);
    X = X + pxLenGraph;

    /* показание скорости */
    if( rx > 1048576 ) {
        double v = rx/1048576.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString("MB/s");
        this->setSpeedRX( s );
    } else if( rx > 1024 ) {
        double v = rx/1024.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString("kB/s");
        this->setSpeedRX( s );
    } else {
        double v = rx*1.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString("B/s");
        this->setSpeedRX( s );
    }

    if( tx > 1048576 ) {
        double v = tx/1048576.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString("MB/s");
        this->setSpeedTX( s );
    } else if( tx > 1024 ) {
        double v = tx/1024.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString("kB/s");
        this->setSpeedTX( s );
    } else {
        double v = tx*1.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString(" B/s");
        this->setSpeedTX( s );
    }

    if( (rx1 / 1024) > 1048576 ) {
        double v = (rx1/1048576.0)/1024.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString("GB");
        this->setTraffRX( s );
    } else if( rx1 > 1048576 ) {
        double v = rx1/1048576.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString("MB");
        this->setTraffRX( s );
    } else if( rx1 > 1024 ) {
        double v = rx1/1024.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString("kB");
        this->setTraffRX( s );
    }

    if( (tx1 / 1024) > 1048576 ) {
        double v = (tx1/1048576.0)/1024.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString("GB");
        this->setTraffTX( s );
    } else if( tx1 > 1048576 ) {
        double v = tx1/1048576.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString("MB");
        this->setTraffTX( s );
    } else if( tx1 > 1024 ) {
        double v = tx1/1024.0;
        QString ss;
        QString s = ss.sprintf("%.2f ",v) + QString("kB");
        this->setTraffTX( s );
    }
    emit changeValueParam();

    this->hide();
    this->show();

    storeTime += timeout;
}

void Monitor::timerStart()
{
    this->initSettings();
    flFistGetTraff = true; /*выставляется для первого считывания байт из интерфейса, во избежании скачка графика*/
    timer.start();
    //qDebug() << "Monitor::timerStart()";
}

void Monitor::timerStop()
{
    timer.stop();
    //qDebug() << "Monitor::timerStop()";
}

void Monitor::firstDataTraf()
{
    if( flFistGetTraff == false ) {
        return;
    }
    GetTraff *gt = new GetTraff( iface );
    TraffData trData = gt->getCurrBytes();
    delete gt;

    rx0 = trData.rx;
    tx0 = trData.tx;
    flFistGetTraff = false;
}


void Monitor::paint(QPainter *paint, const QStyleOptionGraphicsItem *options, QWidget *widget)
{
    Q_UNUSED( options );
    Q_UNUSED( widget );

    Ly = lenghtY - shiftY;
    Lx = lenghtX - shiftX;

    paint->setRenderHints( QPainter::Antialiasing, true );

    //paint->setPen( QColor("gray") );
    //paint->setBrush( QColor("black") );

    //фон
    //paint->drawRect(0, 0, lenghtX, lenghtY );

    this->drawGraph( paint );
}

void Monitor::drawIface( QPainter* paint )
{
    paint->setPen( penIface );
    paint->setFont( fontIface );
    //int y = 35;
    paint->drawText( Lx-50, 30, iface );

    QString iface_str = Utils::pixmapIface( iface );
    QPixmap iface_pic = QPixmap( QString("/opt/QNetMan2/qml/QNetMan2/")+iface_str  );
    paint->drawPixmap( Lx-90, 10, 30, 30, iface_pic );

    if( timer.isActive() == false ) {
        paint->fillRect( 40, 20, 10, 20, QColor("green"));
        paint->fillRect( 50, 20, 10, 20, QColor("red"));
        paint->drawText( 70, 35, "online/offline" );
        return;
    }

    if( flOnline ) {
        paint->fillRect( 40, 20, 20, 20, QColor("green"));
        paint->drawText(70, 35, "online");
    } else {
        paint->fillRect( 40, 20, 20, 20, QColor("red"));
        paint->drawText(70, 35, "offline");
    }
}

void Monitor::drawSystemCoord( QPainter* paint )
{
    paint->setPen( penSC );

    paint->drawLine( shiftX, lenghtY-shiftY, lenghtX, lenghtY-shiftY );
    paint->drawLine( shiftX, 0, shiftX, lenghtY-shiftY );
}

void Monitor::drawGrid( QPainter* paint )
{
    paint->setPen( penGrid );
    paint->setFont( fontGrid );

    int partY = 8;
    float stepLineY = (float)Ly / (float)(partY); /* шаг горизонтально (по оси Y) линии сетки */
    float it = 0.0;
    float currY = (float)Ly;
    int myMaxScaleY = maxScaleY / partY;
    QString txt("");
    while( it < (partY+1) )
    {
        paint->drawLine( shiftX, Ly-currY, lenghtX, Ly-currY );
        if( maxScaleY > 1048576 ) {
            float v = it*myMaxScaleY/1048576.0;
            txt.sprintf( "%.1f MB/s", v );
        } else if( maxScaleY > 1024 ) {
            float v = it*myMaxScaleY/1024.0;
            txt.sprintf( "%.1f KB/s", v );
        } else {
            float v = it*myMaxScaleY;
            txt.sprintf( "%.1f B/s", v );
        }

        int i_it = (int)it;
        if( i_it%2 == 0 ) {
            paint->drawText( shiftX+5, currY+12, txt );
        }

        currY = currY - stepLineY;
        it += 1.0;
    }
}

void Monitor::drawGraph( QPainter* paint )
{
    QColor colorRX( colorStringRX );
    QColor colorTX( colorStringTX );

    //float dx = shiftX + pxLenGraph/2.0;

    /* отрисовка значений, заполняющих каждую деку входящего/исходящего трафика */
    int x = 0;
    //int j = 0;

    if( (viewPointOnGraphRX.length() < 1) || (viewPointOnGraphTX.length() < 1) ) {
        this->drawSystemCoord( paint );
        this->drawGrid( paint );
        this->drawIface( paint );
        return;
    }

    if (__typeGraph == GRAPH_TIME_TYPE)
    {
        QPen penRX( colorRX );
        penRX.setWidth( 2 );

        QPen penTX( colorTX );
        penTX.setWidth( 2 );

        QList<int>::const_iterator itr_r;
        QList<int>::const_iterator itr_t;
        QList<int>::const_iterator itr_ts;

        itr_r = viewPointOnGraphRX.end() - 1;
        itr_t = viewPointOnGraphTX.end() - 1;
        itr_ts = viewTimestampMarker.end() - 1;

        while( (itr_r != (viewPointOnGraphRX.begin())) || (itr_t != (viewPointOnGraphTX.begin())) )
        {
            if( __showRX ) {
                //int valueQueue1 = *(itr_r);
                //int valueQueue0 = *(itr_r+1);
                int valueQueue1 = *(itr_r - 1);
                int valueQueue0 = *(itr_r);
                float r1 = (Ly*(1.0 / maxScaleY))*valueQueue1;
                float r0 = (Ly*(1.0 / maxScaleY))*valueQueue0;
                paint->setPen( penRX );
                paint->drawLine( lenghtX-x, Ly-r0, lenghtX-x-pxLenGraph, Ly - r1 );
            }

            if( __showTX ) {
                //int valueQueue1 = *(itr_t);
                //int valueQueue0 = *(itr_t+1);
                int valueQueue1 = *(itr_t - 1);
                int valueQueue0 = *(itr_t);
                float t1 = (Ly*(1.0 / maxScaleY))*valueQueue1;
                float t0 = (Ly*(1.0 / maxScaleY))*valueQueue0;
                paint->setPen( penTX );
                paint->drawLine( lenghtX-x, Ly-t0, lenghtX-x-pxLenGraph, Ly - t1 );
            }

            int ts = *itr_ts;
            if( ts >= 0 ) {
                paint->setPen( penGrid );
                paint->setFont( fontGrid );
                paint->drawLine( lenghtX-x, 0, lenghtX-x, lenghtY-shiftY);
                paint->drawText( lenghtX-x-10, lenghtY-5, this->humanTimestamp(ts) );
            }

            --itr_r;
            --itr_t;
            --itr_ts;
            x += pxLenGraph;
        } //while
    } else if( __typeGraph == GRAPH_STAT_TYPE ) {
        QPen penRX( colorRX );
        penRX.setWidth( pxLenGraph );

        QPen penTX( colorTX );
        penTX.setWidth( pxLenGraph );

        QList<int>::const_iterator itr_r;
        QList<int>::const_iterator itr_t;
        QList<int>::const_iterator itr_ts;

        itr_r = viewPointOnGraphRX.end()-1;
        itr_t = viewPointOnGraphTX.end()-1;
        itr_ts = viewTimestampMarker.end()-1;
        while( (itr_r != viewPointOnGraphRX.begin()) || (itr_t != viewPointOnGraphTX.begin()) )
        {
            if( __showRX ) {
                int valueQueue = *itr_r;
                float r = (Ly*(1.0 / maxScaleY))*valueQueue;
                paint->setPen( penRX );
                paint->drawLine( lenghtX-x, Ly, lenghtX-x, Ly - r );
            }

            if( __showTX ) {
                int valueQueue = *itr_t;
                float t = (Ly*(1.0 / maxScaleY))*valueQueue;
                paint->setPen( penTX );
                paint->drawLine( lenghtX-x, Ly, lenghtX-x, Ly - t );
            }

            int ts = *itr_ts;
            if( ts >= 0 ) {
                paint->setPen( penGrid );
                paint->setFont( fontGrid );
                paint->drawLine( lenghtX-x, 0, lenghtX-x, lenghtY-shiftY);
                paint->drawText( lenghtX-x-10, lenghtY-5, this->humanTimestamp(ts) );
            }

            --itr_r;
            --itr_t;
            --itr_ts;
            x += pxLenGraph;
        } //while
    } //if...else

    /* отрисовка сетки и системы координат */
    this->drawSystemCoord( paint );
    this->drawGrid( paint );
    this->drawIface( paint );
}

void Monitor::initSettings()
{
    if( qset_here->getTypeGraph() == 0 ) {
        __typeGraph = GRAPH_STAT_TYPE;
    } else if( qset_here->getTypeGraph() == 1 ) {
        __typeGraph = GRAPH_TIME_TYPE;
    } else {
        __typeGraph = GRAPH_STAT_TYPE;
    }

    __showRX = qset_here->isShowRX();
    __showTX = qset_here->isShowTX();

    int ts = qset_here->getTimestamp();
    if( (ts >= 10) && (ts <= 60 ) ) {
        __timestamp = ts;
    } else {
        __timestamp = 30;
    }

    int ri = qset_here->getRefreshInterval();
    if( (ri >= 1) && (ri <= 5 ) ) {
        timeout = ri;
    } else {
        timeout = 1;
    }

    iface = qset_here->getIfaceMonitor();

    colorStringRX = qset_here->getColorRX();
    colorStringTX = qset_here->getColorTX();
}

void Monitor::saveSettings()
{
    //qDebug() << "*** save settings ***";
    qset_here->setRefreshInterval( timeout );

    qset_here->showRX( __showRX );
    qset_here->showTX( __showTX );

    if( __typeGraph == GRAPH_STAT_TYPE ) {
        qset_here->setTypeGraphStat();
    } else if ( __typeGraph == GRAPH_TIME_TYPE ) {
        qset_here->setTypeGraphTime();
    } else {
        qset_here->setTypeGraphStat();
    }

    qset_here->setTimestamp( __timestamp );

    qset_here->setIfaceMonitor( iface );

    qset_here->setColorRX( colorStringRX );
    qset_here->setColorTX( colorStringTX );
}

QString Monitor::humanTimestamp( const int timestamp ) const
{
    QString retSrt;
    int delta_sec = timestamp;
    int Hs = delta_sec / 3600;
    if( Hs != 0 ) {
        delta_sec = delta_sec - Hs*3600;
    }

    int Ms = delta_sec / 60;
    if( Ms != 0 ) {
        delta_sec = delta_sec - 60*Ms;
    }

    int Ss = delta_sec;

    if( Hs == 0 ) {
        if( Ms == 0 ) {
            retSrt.sprintf("%02d", Ss );
        } else {
            retSrt.sprintf( "%d:%02d",  Ms, Ss );
        }
    } else {
        retSrt.sprintf( "%d:%02d:%02d", Hs, Ms, Ss );
    }

    return retSrt;
}
/****************************************************************************/
